home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow_WinXP / VMR / VMRMix / Demonstration.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  14.4 KB  |  429 lines

  1. //------------------------------------------------------------------------------
  2. // File: Demonstration.CPP
  3. //
  4. // Desc: DirectShow sample code
  5. //       Implementation of CDemonstration, 
  6. //       "special effects" module to represent capabilities of VMR.
  7. //       This class is called from CVMRMixDlg by "Play" button.
  8. //       CDemonstration contains CVMRCore member (VMR engine) through which 
  9. //       it performs initialization of the graph builder and presentation.
  10. //
  11. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  12. //------------------------------------------------------------------------------
  13.  
  14. #include "stdafx.h"
  15. #include "Demonstration.h"
  16. #include <math.h>
  17.  
  18. #define DO_NOT_RUN_YET true
  19.  
  20. //------------------------------------------------------------------------------
  21. // Perform 
  22. // Desc: Performs presentation. Just call it from the 'parent' dialog
  23. // Return HRESULT
  24. //------------------------------------------------------------------------------
  25. HRESULT CDemonstration::Perform()
  26. {
  27.     HRESULT hr = S_OK;
  28.     clock_t tStart;
  29.     clock_t tCurrent;
  30.     clock_t tUpdate;
  31.  
  32.     if( false == m_bInitialized )
  33.     {
  34.         hr = Initialize();
  35.     }
  36.     if( FAILED(hr) )
  37.     {
  38.         return hr;
  39.     }
  40.  
  41.     try
  42.     {
  43.         hr = m_pCore->Play();
  44.         if( FAILED(hr) )
  45.         {
  46.             sprintf( m_szMsg, "Failed to run VMR, method returned %s\n", hresultNameLookup(hr));
  47.             OutputDebugString(m_szMsg);
  48.             return hr;
  49.         }
  50.     }
  51.     catch(...)
  52.     {
  53.         OutputDebugString("Unhandled exception in CDemonstration::Perform()\n");
  54.         ShellAbort(m_pCore);
  55.         return E_POINTER;
  56.     }
  57.     
  58.     tStart = clock();
  59.     tCurrent = clock();
  60.     tUpdate = clock();
  61.  
  62.  
  63.     // presentation loop: wait until presentation is over
  64.     // or user closed the window and VMRCore is inactive
  65.     while( (tCurrent - tStart) / CLOCKS_PER_SEC <  m_MList.GetAvgDuration() / 10000000L &&
  66.             m_pCore->IsActive() )
  67.     {
  68.         Sleep(10);
  69.         UpdateStreams(tStart);
  70.         tCurrent = clock();
  71.     }// while
  72.  
  73.     return S_OK;
  74. }
  75.  
  76. //------------------------------------------------------------------------------
  77. // Initialize()
  78. // Desc: Initializes demonstration; fills start parameters, 
  79. //       creates the graph for VMR; renders files
  80. // Return: HRESULT
  81. //------------------------------------------------------------------------------
  82. HRESULT CDemonstration::Initialize()
  83. {
  84.     HRESULT hr = S_OK;
  85.     LONGLONG llCurrent = 0L;
  86.     LONGLONG llStop = 0L;
  87.     LONGLONG llDelay = 0L;
  88.     clock_t tStart;
  89.  
  90.     // calculate playback time
  91.     m_MList.AdjustDuration();   
  92.                                 
  93.     m_MList.SetInitialParameters();
  94.  
  95.     // create VMRCore
  96.     m_pCore = new CVMRCore(m_pDlg, &m_MList ); 
  97.  
  98.     tStart = clock();
  99.  
  100.     if( !m_pCore)
  101.     {
  102.         return E_OUTOFMEMORY;
  103.     }
  104.  
  105.     // here, VMRCore creates the graph and if successfully, runs IMediaControl
  106.     // for the first file from the media list
  107.     hr = m_pCore->Play(DO_NOT_RUN_YET); 
  108.     if(FAILED(hr))
  109.     {
  110.         return hr;
  111.     }
  112.  
  113.     // if user selected "show bitmap" option, load the bitmap
  114.     // from the resource and apply color key
  115.     if( m_pDlg->IsBitmapToUse())
  116.     {
  117.         hr = SetAlphaBitmapColorKey(IDB_BITMAP_LOGO);
  118.  
  119.         if(FAILED(hr))
  120.         {
  121.             OutputDebugString("Failed to SetAlphaBitmapColorKey() in CDemonstration::Initialize()\n");
  122.             return E_INVALIDARG;
  123.         }
  124.     }
  125.  
  126.     m_bInitialized = true;
  127.  
  128.     return S_OK;
  129. }
  130.  
  131. //------------------------------------------------------------------------------
  132. //  SetAlphaBitmapColorKey
  133. //  Desc: initializes proper members of VMRALPHABITMAP for solor key support
  134. //  Parameters: [in]    UINT ImageID - resource ID
  135. //  Return: HRESULT
  136. //------------------------------------------------------------------------------
  137. HRESULT CDemonstration::SetAlphaBitmapColorKey(UINT ImageID)
  138. {
  139.     HRESULT hr;
  140.  
  141.     if( ! m_pCore )
  142.     {
  143.         OutputDebugString("Function SetAlphaBitmapColorKey() is called before initializing m_pCore\n");
  144.         return E_INVALIDARG;
  145.     }
  146.     // prepare the valid default bitmap 
  147.     if (GetValidVMRBitmap(ImageID) != FNS_PASS)
  148.     {
  149.         OutputDebugString("Unable to get a valid VMRALPHABITMAP\n");
  150.         return E_INVALIDARG;
  151.     }
  152.  
  153.     m_sBmpParams.fAlpha = 1.0f;
  154.     m_sBmpParams.clrSrcKey = RGB(255,255,255);
  155.     m_sBmpParams.dwFlags |= VMRBITMAP_SRCCOLORKEY;
  156.  
  157.     try 
  158.     {
  159.         hr = m_pCore->GetMixerBitmap()->SetAlphaBitmap(&m_sBmpParams);
  160.  
  161.         if( FAILED(hr) )
  162.         {
  163.             return hr;
  164.         }
  165.     } // try
  166.     catch(...)
  167.     {
  168.         return ShellAbort(m_pCore); 
  169.     }
  170.     return S_OK;
  171. }
  172.  
  173. //------------------------------------------------------------------------------
  174. //  GetValidVMRBitmap
  175. //  Desc: creates bitmap compatible with VMR
  176. //  Parameters: [in]    UINT ImageID - resource ID
  177. //              [out]   VMRALPHABITMAP * vmrBmp - what IVMRMixerBitmap uses 
  178. //  Return: HRESULT
  179. //------------------------------------------------------------------------------
  180. HRESULT CDemonstration::GetValidVMRBitmap(UINT ImageID)
  181. {
  182.     HRESULT hr = S_OK;
  183.     long cx, cy;
  184.     HDC hdc;
  185.     HBITMAP hbmpVmr;
  186.     BITMAP bmp;
  187.  
  188.     hr = m_pCore->GetVMRWndless()->GetNativeVideoSize(&cx, &cy, NULL, NULL);
  189.     if( FAILED(hr) )
  190.     {
  191.         OutputDebugString("Failed in GetNativeVideoSize()\n");
  192.         return hr;
  193.     }
  194.  
  195.     // get compatible DC
  196.     hdc = GetDC(m_pCore->GetClientHwnd());
  197.     
  198.     m_hbmp = CreateCompatibleBitmap(hdc, cx, cy); /*** RELEASE ***/
  199.     
  200.     hbmpVmr = (HBITMAP)LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(ImageID),IMAGE_BITMAP,0,0,/*LR_LOADFROMFILE|*/LR_CREATEDIBSECTION);
  201.     if( !hbmpVmr )
  202.     {
  203.         OutputDebugString("Failed to load resource\n");     
  204.         DeleteObject(m_hbmp);
  205.         return E_INVALIDARG;
  206.     }
  207.  
  208.     // Get size of the bitmap
  209.     GetObject( hbmpVmr, sizeof(bmp), &bmp );
  210.     
  211.     HDC hdcBmp = CreateCompatibleDC(hdc); /*** RELEASE ***/
  212.     HDC hdcVMR = CreateCompatibleDC(hdc);
  213.  
  214.     ReleaseDC(m_pCore->GetClientHwnd(), hdc);
  215.  
  216.     HBITMAP hbmpold = (HBITMAP)SelectObject(hdcBmp, m_hbmp);// in hdcBmp, select hbmp
  217.     hbmpVmr = (HBITMAP)SelectObject(hdcVMR, hbmpVmr);// in hdcVmr, select hbmpVmr (the pic we loaded)
  218.  
  219.     BitBlt(hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcVMR, 0, 0, SRCPAINT);// put loaded pic from hdcVmr to hdcBmp
  220.     DeleteObject(SelectObject(hdcVMR, hbmpVmr));// ok, we do not need hbmpVmr any more
  221.     DeleteDC(hdcVMR);
  222.  
  223.     RECT rc;
  224.  
  225.     ZeroMemory(&m_sBmpParams, sizeof(VMRALPHABITMAP) );
  226.     m_sBmpParams.dwFlags = VMRBITMAP_HDC;
  227.     m_sBmpParams.hdc = hdcBmp;
  228.  
  229.     // set source rectangle (entire original bitmap)
  230.     SetRect(&rc, 0, 0, bmp.bmWidth, bmp.bmHeight);
  231.     m_sBmpParams.rSrc = rc;
  232.  
  233.     float fCoeff = 0.2f + 1.7f * (float)rand()/RAND_MAX;
  234.     // set destination rectangle (keeping aspect ratio of the original image)
  235.     // please note that normalized rect is always in [0.0, 1.0] range for
  236.     // all its members
  237.     m_sBmpParams.rDest.left = 0.f;  
  238.     m_sBmpParams.rDest.top = 0.f;
  239.     m_sBmpParams.rDest.right = 0.9f*(float)bmp.bmWidth / (float)cx;
  240.     m_sBmpParams.rDest.bottom = 0.9f*(float)bmp.bmHeight / (float)cy;
  241.     m_sBmpParams.fAlpha = 0.5f;
  242.  
  243.     // quite important, otherwise VMR would give error
  244.     m_sBmpParams.pDDS = NULL;
  245.  
  246.     // Note: this demo uses bitmap directly, but often it is better to create
  247.     // DirectDrawSurface of appropriate format and set m_sBmpParams.pDDS to it 
  248.     // (especially if you experience performance issues)
  249.  
  250.     return S_OK;
  251. }
  252.  
  253.  
  254. //------------------------------------------------------------------------------
  255. //  UpdateStreams
  256. //  Desc: updates presentation parameters (destination rectangles and alpha level)
  257. //        for each media file
  258. //  Parameters: clock_t tStart -- presentation start; used as a 'time' variable 
  259. //              in calculations
  260. //  Return: HRESULT
  261. //------------------------------------------------------------------------------
  262. HRESULT CDemonstration::UpdateStreams(clock_t tStart)
  263. {
  264.     HRESULT hr = S_OK;
  265.     int i;
  266.     clock_t tCurrent;
  267.     NORMALIZEDRECT rectD0;
  268.     NORMALIZEDRECT rectD;
  269.     NORMALIZEDRECT rectDRes; 
  270.     double Alpha0;
  271.     double Alpha;
  272.  
  273.     ASSERT( tStart >0 );
  274.  
  275.     for( i=0; i< this->m_MList.Size(); i++)
  276.     {
  277.         if( false == m_MList.GetItem(i)->m_bInUse)
  278.             continue;
  279.  
  280.         tCurrent = clock() - tStart;
  281.  
  282.         rectD0 = m_MList.GetItem(i)->m_rD;
  283.         Alpha0 = m_MList.GetItem(i)->m_fAlpha;
  284.         
  285.         Alpha = 1.f;
  286.         rectD.left = rectD.top = 0.f;
  287.         rectD.right = rectD.bottom = 1.f;
  288.  
  289.         FountainPath(   tCurrent, 
  290.                         (long)(m_MList.GetAvgDuration() / 10000000 * CLOCKS_PER_SEC),
  291.                         i,
  292.                         rectD0,
  293.                         Alpha0, 
  294.                         &rectD, 
  295.                         &Alpha);
  296.             
  297.         hr = m_pCore->GetMixerControl()->SetAlpha(i, (float)Alpha);
  298.         if( !SUCCEEDED(hr))
  299.         {
  300.             sprintf( m_szMsg, "Failure in CDemonstration::UpdateStreams, GetMixerControl()->SetAlpha, method returned %s\n",
  301.                 hresultNameLookup(hr));
  302.             OutputDebugString(m_szMsg);
  303.         }
  304.         hr = m_pCore->GetMixerControl()->SetOutputRect(i, &rectD);
  305.         if( !SUCCEEDED(hr))
  306.         {
  307.             sprintf( m_szMsg, "Failure in CDemonstration::UpdateStreams, GetMixerControl()->SetOutputRect, method returned %s\n",
  308.                 hresultNameLookup(hr));
  309.             OutputDebugString(m_szMsg);
  310.         }
  311.  
  312.         hr = m_pCore->GetMixerControl()->GetOutputRect(i, &rectDRes);
  313.         if( !SUCCEEDED(hr))
  314.         {
  315.             sprintf( m_szMsg, "Failure in CDemonstration::UpdateStreams, GetMixerControl()->GetOutputRect, method returned %s\n",
  316.                 hresultNameLookup(hr));
  317.             OutputDebugString(m_szMsg);
  318.         }
  319.         else
  320.         {
  321.             if( fabs(rectD.top - rectDRes.top) > 0.01 ||
  322.                 fabs(rectD.bottom - rectDRes.bottom) > 0.01 ||
  323.                 fabs(rectD.left - rectDRes.left) > 0.01 ||
  324.                 fabs(rectD.right - rectDRes.right) > 0.01  )
  325.             {
  326.                 sprintf( m_szMsg, "Failed invalidation of SetOutputRect(): required [l,t,r,b] = [%f,%f,%f,%f] and returned [%f,%f,%f,%f]\n",
  327.                     rectD.left, rectD.top, rectD.right, rectD.bottom,
  328.                     rectDRes.left, rectDRes.top, rectDRes.right, rectDRes.bottom );
  329.                 OutputDebugString(m_szMsg);
  330.             }
  331.         }// else
  332.  
  333.     }// for
  334.  
  335.     return hr;
  336. }
  337.  
  338.  
  339. //------------------------------------------------------------------------------
  340. // Name: FountainPath
  341. // Purpose: creates 'movie fountain' effect; for each stream, center point 
  342. //          moves by a random ellipse around the center of a playback window;
  343. //          size and alpha-level of stream's output rect changes by cosine with 
  344. //          some random initial delay (to desynchronize streams) 
  345. // Parameters:  
  346. //              [IN]    long t - current timestamp (any units, we use relative time)
  347. //              [IN]    long T - expected total playback time (in the same units as t)
  348. //              [IN]    int n - id of particular stream we want to set
  349. //              [IN]    NORMALIZEDRECT r0 - original OutputRect of the stream
  350. //              [IN]    double A0 - original alpha level (used as a parameter for smoothly 
  351. //                                  changing alpha level)
  352. //              [OUT]   NORMALIZEDRECT * pR - dest. part of playback window
  353. //              [OUT]   double * pA - new alpha level
  354. //------------------------------------------------------------------------------
  355. void CDemonstration::FountainPath(  long t, 
  356.                                     long T, 
  357.                                     int n, 
  358.                                     NORMALIZEDRECT r0,  
  359.                                     double A0, 
  360.                                     NORMALIZEDRECT * pR, 
  361.                                     double * pA)
  362. {
  363.     double cx0;     // original center of the output rect, in normalized coordinates
  364.     double cy0;
  365.     double cx;      // new center of the output rect, in normalized coordinates
  366.     double cy;
  367.     double cx1;     // auxiliary center of the output rect, in normalized coordinates
  368.     double cy1;
  369.     double L0;      // original half-diagonal measure of the rectangle
  370.     double w;       // orig. rect width
  371.     double h;       // orig. rect height
  372.     double beta;    // shift in cosine for L(t). see below
  373.     double L;       // new half-diagonal measure of the rectangle
  374.     double tau;     // time in relative units
  375.     double gamma;   // shift in sine for A(t). see below
  376.     double coeff;   // coefficient that is used to create 'mirror-flip' effect
  377.     double dx;      // new half-width
  378.     double dy;      // new half-heights
  379.  
  380.     // relative time,  to have about 3 periods over the total playtime
  381.     tau = 18.0 * (double)t / T;
  382.  
  383.     // alpha level, A = 0.2 + 0.8 sin( tau + gamma) where gamma is such that A(0)=A0
  384.     gamma = (A0 - 0.2)/0.8;
  385.     gamma = (gamma < -1.) ? -1. : gamma;
  386.     gamma = (gamma > 1. ) ?  1. : gamma;
  387.     gamma = asin( gamma);
  388.     *pA = 0.6 + 0.4 * sin(tau + gamma + A0);
  389.  
  390.     cx0 = (r0.left + r0.right)/2.;
  391.     cy0 = (r0.top + r0.bottom)/2.;
  392.     w = r0.right - r0.left;
  393.     h = r0.bottom - r0.top;
  394.     L0 = 0.5 * sqrt(w*w + h*h);
  395.  
  396.     L0 = (L0 < 0.0001) ? 0.1 : L0;
  397.     // now rectangle. Its half-diagonal measure L = 0.1 + 0.7 cos( tau + beta)
  398.     // where beta is such that L(0) = LO;
  399.     beta = (L0 - 0.1)/0.7;
  400.     beta = (beta < -1.) ? -1. : beta;
  401.     beta = (beta >  1.) ?  1. : beta;
  402.     beta = acos( beta);
  403.     L = 0.35 + 0.45 * cos( tau + beta + 3.*A0);
  404.  
  405.     // center of the rectangle is moving by ellips
  406.     // cx = cx0 + (-1)^n 0.1 sin(tau);
  407.     // cy = cy0 - 0.2 + 0.2 cos( tau);
  408.     // and turn it buy... say, theta = 7.85 A0 - 1.57;
  409.     coeff = (n%2) ? -1. : 1.;
  410.     cx1 = cx0 + coeff * 0.2 * sin(tau + A0);
  411.     cy1 = cy0 - 0.05 + 0.2 * cos( tau + A0);
  412.  
  413.     // the lines below are unnecessary, but we could want some
  414.     // additional transformation here, like turn trajectory ellipse
  415.     // by some angle
  416.     cx = cx1;
  417.     cy = cy1;
  418.  
  419.     dx = L * w / L0;
  420.     dy = L * h / L0;
  421.  
  422.     pR->left    = (float)(cx - dx);
  423.     pR->right   = (float)(cx + dx);
  424.     pR->top     = (float)(cy - dy);
  425.     pR->bottom  = (float)(cy + dy);
  426. }
  427.  
  428.  
  429.